SpringMVC 控制器方法(handler)适配器 - HandlerAdapter

SpringMVC 控制器方法(handler)适配器 - HandlerAdapter

简单的源码分析

HandlerAdapter 是一个 MVC 框架 SPI 接口,通过此接口,我们可以高度自定义核心 MVC 工作流。

(控制器 handler 可以是任意类型),任何一种类型的 handler 都必须有一个 HandlerAdapter 支持,否则此种类型的 handler 将无法解析请求,

通过 HandlerAdapter 接口,可以实现对 DispatcherServlet 的无限扩展。DispatcherServlet 通过 HandlerAdapter 调用 handler,这意味着 DispatcherServlet 不包含特定于任何类型的 handler 的代码。这让 DispatcherServlet 保持了低耦合的效果。

注意,handler 可以是任意类型,当然也可以是 Object 类型。这是为了使来自其他框架的 handler 无需额外编码就可以与 SpringMVC 框架集成,并且允许不实现任何特定接口的带特定注解的 handler。

此接口不适用于应用程序开发人员。它适用于希望开发自己的 web 工作流的处理程序的开发人员。

接口源码:

public interface HandlerAdapter {

    //  判断是否支持特定类型的handler,一个HandlerAdapter一般支持持一个类型的 handler
    boolean supports(Object handler);

    //  根据传入的 handler 处理传入的 request 请求,并最终返回一个 ModelAndView, 这个 handler 一般都是先通过  supports 方法判断过此HandlerAdapter支持的handler.
    // 具体的实现非常自由,想做什么都可以
    // 一般调用 handler 处理  request 前会做非常多的准备工作,
    @Nullable
    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

    // 不知道啥意思
    long getLastModified(HttpServletRequest request, Object handler);

}

一般我们都要调用 HandlerAdapter#supports 方法来检查当前 HandlerAdapter 是否支持此 handler,如果支持,才会调用 HandlerAdapter#handle 方法来处理请求

类继承树:

适配器的意义

一般 handler(处理器)这个概念是没有固定类型的,大部分的时候,是控制器方法(@Controller 修饰的类中的方法),有的时候是 DefaultServletHttpRequestHandler,有的时候是 ParameterizableViewController,所以,我们只能用 Object 来承接 handler 这个概念,同时,我们还需要对不同的类型的 handler 进行适配,让各种类型的 handler 都可以适配进统一的流程处理(DispatcherServlet#doDispatch),于是适配器 HandlerAdapter 应运而生。,同时在适配器中也可以进行一些调用 handler 前的前置工作,比如,在调用控制器方法这一类 handler 的时候,会进行控制器方法参数的填充,同时进行参数验证等等。

我们可以通过 HandlerAdapter#supports 方法查看此适配器支持何种类型的 handler,

初始化

DispatcherServlet#initHandlerAdaptersDispatcherServlet#getDefaultStrategies

DispatcherServlet#initHandlerAdapters 请看《SpringMVC-DispatcherServlet 源码分析.md》的 initStrategies 小节

在《SpringMVC- 第五篇:视图》就有过关于 DispatcherServlet#getDefaultStrategies 的研究。

一般用不到 DispatcherServlet#getDefaultStrategies,通过注解配置 SpringMVC 的时候(实际上在 WebMvcConfigurationSupport 中),会自动注入在应用上下文中注入默认几个 HandlerAdapter 的相应类型的 Bean,

具体生效

doDispatch 执行流程

DispatcherServlet#doDispatch 中的 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

DispatcherServletgetHandlerAdapter 方法则是通过遍历字段 handlerAdapters,调用 HandlerAdaptersupports 方法,检查适配器是否支持当前 handler,只要找到了支持的适配器就直接返回,所以 handlerAdapters 中的 HandlerAdapter 的顺序很重要。

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    if (this.handlerAdapters != null) {
        for (HandlerAdapter adapter : this.handlerAdapters) {
            // 按照排序来一个个尝试,如果是当前适配器支持的类型,则直接使用此适配器
            if (adapter.supports(handler)) {
                return adapter;
            }
        }
    }
    throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

应用上下文中会注入默认的相应类型的 Bean,比如在 WebMvcConfigurationSupport 中,该有的都有四种。

比 xml 配置 SpringMVC 多了一类,而且顺序也不一样,

通过 XML 配置的 HandlerAdapter

RequestMappingHandlerAdapter

具体请看《SpringMVC-RequestMappingHandlerAdapter 源码解析.md

HttpRequestHandlerAdapter

有时间再来研究,TODO

SimpleControllerHandlerAdapter

有时间再来研究,TODO